﻿using System;
using System.Linq;
using System.Threading;
using ESRI.ArcGIS.Client.Async;
using ESRI.ArcGIS.Client.Tasks;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ArcGIS.Client.Async.Tests
{
    [TestClass]
    public class QueryTaskTests : SilverlightTest
    {
        private Query _query;
        private QueryTask _queryTask;

        [TestInitialize]
        public void Initialize()
        {
            _query = new Query { Text = "New" };
            _queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/5")
            {
                DisableClientCaching = true
            };
        }

        [TestMethod, Asynchronous, Description("Sample: http://resources.arcgis.com/en/help/silverlight-api/samples/start.htm#QueryWithoutMap")]
        public async void Execute()
        {
            var result = await _queryTask.ExecuteTaskAsync(_query);
            Assert.IsTrue(result.FeatureSet.Any());
            TestComplete();
        }

        [TestMethod, Asynchronous, Description("Wrong URL: should throw an exception")]
        public async void ExecuteWrongQuery()
        {
            var badQueryTask = new QueryTask("http://WRONGSERVER.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/5")
            {
                DisableClientCaching = true
            };
            try
            {
                await badQueryTask.ExecuteTaskAsync(_query);
                Assert.Fail("Should not reach this line");
            }
            catch (Exception)
            {
                TestComplete();
            }
        }

        [TestMethod, Asynchronous, Description("Run query execution and cancel it after few milliseconds. Await should throw an OperationCanceledException.")]
        public async void CancelOperation()
        {
            var cts = new CancellationTokenSource();
            try
            {
                var result = _queryTask.ExecuteTaskAsync(_query, cts.Token);
                // Query is supposed to execute longer then 5 milliseconds
                cts.CancelAfter(TimeSpan.FromMilliseconds(5));
                await result;
                Assert.Fail("Should not reach this line");
            }
            catch (OperationCanceledException)
            {
                TestComplete();
            }
            catch (Exception)
            {
                Assert.Fail();
            }
        }

        [TestMethod, Asynchronous, Description("Should not throw.")]
        public async void CancelOperationAfterCompletion()
        {
            var cts = new CancellationTokenSource();
            try
            {
                var result = _queryTask.ExecuteTaskAsync(_query, cts.Token);
                await result;
                cts.Cancel();
                TestComplete();
            }
            catch (Exception)
            {
                Assert.Fail();
            }
        }

        [TestMethod, Asynchronous, Description("Should throw an OperationCanceledException.")]
        public async void CancelOperationBeforeStart()
        {
            var cts = new CancellationTokenSource();
            cts.Cancel();

            try
            {
                // ReSharper disable once CSharpWarnings::CS4014
                await _queryTask.ExecuteTaskAsync(_query, cts.Token);
                Assert.Fail();
            }
            catch (OperationCanceledException)
            {
                TestComplete();
            }
            catch (Exception)
            {
                Assert.Fail();
            }
        }

        [TestMethod, Asynchronous]
        public async void ExecuteCount()
        {
            var result = await _queryTask.ExecuteCountTaskAsync(_query);
            Assert.IsTrue(result.Count > 0);
            TestComplete();
        }
    }
}